﻿using ImTools;
using Microsoft.Win32;
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Common;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Xml.Linq;
using static WpfKeyFrame.Views.PublicClasses;

namespace WpfKeyFrame.ViewModels
{
    public class MainProcessWindowViewModel : BindableBase
    {
        #region +取景框位置、大小
        private double _quJingLeft;
        public double QuJingKuangLeft
        {
            get { return _quJingLeft; }
            set { SetProperty(ref _quJingLeft, (int)value); }
        }
        private double _quJingTop;
        public double QuJingKuangTop
        {
            get { return _quJingTop; }
            set { SetProperty(ref _quJingTop, (int)value); }
        }

        private double _quJingWidth = 200;
        public double QuJingKuangWidth
        {
            get { return _quJingWidth; }
            set { SetProperty(ref _quJingWidth, (int)value); }
        }
        private double _quJingHeight = 200;
        public double QuJingKuangHeight
        {
            get { return _quJingHeight; }
            set { SetProperty(ref _quJingHeight, (int)value); }
        }
        #endregion
        private bool _isMakeToBinary;
        public bool IsMakeToBinary
        {
            get { return _isMakeToBinary; }
            set
            {
                SetProperty(ref _isMakeToBinary, value);
                if (value) BitmapPng = ConvertToBinary(new WriteableBitmap(_bitmapImage), BinaryThresholdValue);
                else BitmapPng = new WriteableBitmap(_bitmapImage);
            }
        }
        private int _binaryThresholdValue; // 二值化图像时的阀值
        public int BinaryThresholdValue
        {
            get { return _binaryThresholdValue; }
            set
            {
                if (value > 0xff) value = 0xff;
                SetProperty(ref _binaryThresholdValue, value);
                if (IsMakeToBinary) BitmapPng = ConvertToBinary(new WriteableBitmap(_bitmapImage), value);
            }
        }
        private byte _verticalThresholdValue;
        public byte VerticalThrosholdValue // 垂直辅助线阀值，例如：当某一行每个像素进行“与”运算的结果，小于阀值时，则判定为空白行；大于时，则判定不是空白行。
        {
            get { return _verticalThresholdValue; }
            set { SetProperty(ref _verticalThresholdValue, value); MakeHelpLine(); }
        }
        private byte _horizontalThresholdValue;
        public byte HorizontalThrosholdValue // 水平辅助线阀值，例如：当某一行每个像素进行“与”运算的结果，小于阀值时，则判定为空白行；大于时，则判定不是空白行。
        {
            get { return _horizontalThresholdValue; }
            set { SetProperty(ref _horizontalThresholdValue, value); MakeHelpLine(); }
        }
        private WriteableBitmap _bitmapPng;
        public WriteableBitmap BitmapPng // 图像图层
        {
            get { return _bitmapPng; }
            set { SetProperty(ref _bitmapPng, value); }
        }
        private WriteableBitmap _bitmapPngCopy;
        public WriteableBitmap BitmapPngCopy // 辅助线图层
        {
            get { return _bitmapPngCopy; }
            set { SetProperty(ref _bitmapPngCopy, value); }
        }
        private WriteableBitmap _strokeBitmap;
        public WriteableBitmap StrokeBitmap // 轮廓线图层
        {
            get { return _strokeBitmap; }
            set { SetProperty(ref _strokeBitmap, value); }
        }
        private string _LineLocal;
        public string LineLocal
        {
            get { return _LineLocal; }
            set { SetProperty(ref _LineLocal, value); }
        }

        private string _animaViewBox;  // 预览框ImageBrush的ViewBox数据
        public string AnimaViewBox
        {
            get { return _animaViewBox; }
            set { SetProperty(ref _animaViewBox, value); }
        }
        public List<int> HorizontalLocal; // 水平辅助线行坐标
        public List<int> VerticalLocal; // 垂直辅助线列坐标
        private BitmapImage _bitmapImage; // 已加载的原始图像

        private ObservableCollection<FrameClass> _frameList;
        public ObservableCollection<FrameClass> FrameList  // 动画帧存储列表
        {
            get { return _frameList; }
            set { SetProperty(ref _frameList, value); }
        }
        public List<FrameClass> SelectedFrames;
        private ObservableCollection<string> _storyCodeList;
        public ObservableCollection<string> StoryCodeList
        {
            get { return _storyCodeList; }
            set { SetProperty(ref _storyCodeList, value); }
        }
        public DelegateCommand MakeHelpLineCommand { get; private set; } // 制作辅助线
        public DelegateCommand AlignHelpLineCommand { get; private set; } // 对齐辅助线
        public DelegateCommand MakeFrameCommand { get; private set; } // 制作帧
        public DelegateCommand MakeCodeCommand { get; private set; } // 生成代码
        public DelegateCommand DeleteAllFrameCommand { get; private set; } // 删除全部帧
        public DelegateCommand DeleteFrameCommand { get; private set; } // 删除选中帧
        public DelegateCommand OpenImageFileCommand { get; private set; } // 打开图像文件
        public DelegateCommand NoiseReductionCommand { get; private set; } // 二值化图像降噪
        public DelegateCommand StrokeCommand { get; private set; } // 描边

        /// <summary>
        /// 打开新图像文件
        /// </summary>
        private void OpenImageFile()
        {
            string filePath = "";
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Title = "";
            dialog.Filter = "PNG|*.PNG";
            if (dialog.ShowDialog() == true)
            {
                filePath = dialog.FileName;
                _bitmapImage = new BitmapImage(new Uri(filePath, UriKind.RelativeOrAbsolute));
                BitmapPng = new WriteableBitmap(_bitmapImage);
                BitmapPngCopy = new WriteableBitmap(BitmapPng.PixelWidth, BitmapPng.PixelHeight, BitmapPng.DpiX, BitmapPng.DpiY, BitmapPng.Format, BitmapPng.Palette);
                StrokeBitmap = new WriteableBitmap(BitmapPng.PixelWidth, BitmapPng.PixelHeight, BitmapPng.DpiX, BitmapPng.DpiY, BitmapPng.Format, BitmapPng.Palette);
                QuJingKuangWidth = 200;
                QuJingKuangHeight = 200;
                HorizontalLocal.Clear();
                VerticalLocal.Clear();
                HorizontalThrosholdValue = 0;
                VerticalThrosholdValue = 0;
                IsMakeToBinary = false;
                BinaryThresholdValue = 0;
            }

        }

        string pngFile = @"Resourse/Demo.png"; // 示例图像文件
        public MainProcessWindowViewModel()
        {
            QuJingKuangWidth = 200;
            QuJingKuangHeight = 200;
            MakeHelpLineCommand = new DelegateCommand(MakeHelpLine);
            AlignHelpLineCommand = new DelegateCommand(AlingHelpLine);
            MakeFrameCommand = new DelegateCommand(MakeFrame);
            MakeCodeCommand = new DelegateCommand(MakeCode);
            DeleteAllFrameCommand = new DelegateCommand(DeleteAllFrame);
            DeleteFrameCommand = new DelegateCommand(DeleteFrame);
            OpenImageFileCommand = new DelegateCommand(OpenImageFile);
            NoiseReductionCommand = new DelegateCommand(NoiseReductionButtonClick);
            StrokeCommand = new DelegateCommand(StrokeButtonClick);

            //_bitmapImage = GetBitmapImage(pngFile);
            _bitmapImage = new BitmapImage(new Uri(pngFile, UriKind.RelativeOrAbsolute));
            BitmapPng = new WriteableBitmap(_bitmapImage);
            BitmapPngCopy = new WriteableBitmap(BitmapPng.PixelWidth, BitmapPng.PixelHeight, BitmapPng.DpiX, BitmapPng.DpiY, BitmapPng.Format, BitmapPng.Palette);
            HorizontalLocal = new List<int>(); //水平辅助线位置
            VerticalLocal = new List<int>(); // 垂直辅助线位置
            FrameList = new ObservableCollection<FrameClass>();
            StoryCodeList = new ObservableCollection<string>();
            SelectedFrames = new List<FrameClass>();
            ImageBrushViewboxStory = new Storyboard();

        }

        private void StrokeButtonClick()
        {
            StrokeBitmap = Stroke(BitmapPng); // 描边
        }

        private void NoiseReductionButtonClick()
        {
            if (IsMakeToBinary) BitmapPng = DeNoising(BitmapPng, BinaryThresholdValue);
        }



        private void DeleteFrame()
        {
            foreach (FrameClass frame in SelectedFrames)
            {
                if (FrameList.Contains(frame))
                {
                    FrameList.Remove(frame);
                }
            }
        }

        private void DeleteAllFrame()
        {
            FrameList.Clear();
        }

        /// <summary>
        /// 制作动画帧
        /// </summary>
        private void MakeFrame()
        {
            FrameClass frame = new FrameClass()
            {
                FrameBitmap = BitmapPng,
                FrameWidth = QuJingKuangWidth,
                FrameHeight = QuJingKuangHeight,
                FrameLeft = QuJingKuangLeft,
                FrameTop = QuJingKuangTop,
                FrameViewbox = string.Format($"{QuJingKuangLeft + QuJingKuangWidth / 2},{QuJingKuangTop + QuJingKuangHeight / 2},0,0")
            };
            FrameList.Add(frame);
            AnimaViewBox = frame.FrameViewbox; // 动画预览框
        }

        #region 生成动画代码
        /// <summary>
        /// 生成动画代码
        /// </summary>
        private void MakeCode()
        {
            if (FrameList.Count == 0) return;
            StoryCodeList.Clear();
            StoryCodeList.Add("<!-- 以下代码为动画资源 -->");
            StoryCodeList.Add("<Storyboard x:Key=\"FramStorybord\" RepeatBehavior=\"Forever\">");
            StoryCodeList.Add("<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty=\"(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)\">");
            foreach (FrameClass frame in FrameList)
            {
                StoryCodeList.Add($"<DiscreteDoubleKeyFrame KeyTime=\"{frame.FrameBeginTime,0:T}\" Value=\"{frame.FrameLeft * -1}\"/>");
            }
            StoryCodeList.Add("</DoubleAnimationUsingKeyFrames>");
            StoryCodeList.Add("<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty=\"(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)\">");
            foreach (FrameClass frame in FrameList)
            {
                StoryCodeList.Add($"<DiscreteDoubleKeyFrame KeyTime=\"{frame.FrameBeginTime,0:T}\" Value=\"{frame.FrameTop * -1}\"/>");
            }
            StoryCodeList.Add("</DoubleAnimationUsingKeyFrames></Storyboard>");
            StoryCodeList.Add("<!-- 以下代码为窗口动画承载控件 -->");

            StoryCodeList.Add($"<ScrollViewer Width=\"{QuJingKuangWidth}\" Height=\"{QuJingKuangHeight}\" Background=\"Black\" VerticalScrollBarVisibility=\"Hidden\" HorizontalScrollBarVisibility=\"Hidden\">");
            StoryCodeList.Add($"<Grid Width=\"{_bitmapImage.PixelWidth}\" Height=\"{_bitmapImage.PixelHeight}\">");
            StoryCodeList.Add($"<Image x:Name=\"previewImge\" Source=\"{pngFile}\" AutomationProperties.AcceleratorKey=\"Raw\" RenderTransformOrigin=\"0.5,0.5\" Stretch=\"None\">");
            StoryCodeList.Add("<Image.RenderTransform>\n<TransformGroup>\n<ScaleTransform/>\n<SkewTransform/>\n<RotateTransform/>\n<TranslateTransform X=\"1\" Y=\"1\"/>\n</TransformGroup >\n</Image.RenderTransform>");
            StoryCodeList.Add("<Image.Triggers>\n<EventTrigger RoutedEvent=\"Image.MouseUp\">\n<BeginStoryboard Storyboard=\"{DynamicResource FramStorybord}\"/>\n</EventTrigger>\n</Image.Triggers>");
            StoryCodeList.Add("</Image>\n</Grid>\n</ScrollViewer>");
            StoryCodeList.Add("\n");

            try
            {
                StreamWriter sw = new StreamWriter("D:\\StoryBoard.txt");
                foreach (string str in StoryCodeList)
                {
                    sw.WriteLine(str);
                }
                sw.Close();
            }
            finally
            {
                Process.Start("NotePad.exe", "D:\\StoryBoard.txt");
            }
        }
        #endregion

        private Storyboard _imageBrushViewboxStory;
        public Storyboard ImageBrushViewboxStory
        {
            get { return _imageBrushViewboxStory; }
            set { SetProperty(ref _imageBrushViewboxStory, value); }
        }

        #region 辅助线生成函数
        /// <summary>
        /// 生在辅助线
        /// </summary>
        private void MakeHelpLine()
        {
            BitmapPng = new WriteableBitmap(_bitmapImage);
            BitmapPngCopy = new WriteableBitmap(BitmapPng.PixelWidth, BitmapPng.PixelHeight, BitmapPng.DpiX, BitmapPng.DpiY, BitmapPng.Format, BitmapPng.Palette);
            int width = BitmapPng.PixelWidth; int height = BitmapPng.PixelHeight;
            int pixelUseMemoryCount = BitmapPng.Format.BitsPerPixel; // 计算每个像素使用的字体数
            HorizontalLocal.Clear();
            VerticalLocal.Clear();
            try
            {
                BitmapPng.Lock();
                BitmapPngCopy.Lock();
                unsafe // 不安全代码
                {
                    IntPtr pBackBuffer = BitmapPng.BackBuffer; // 内存指针基址
                    IntPtr pBackBufferOfCopy = BitmapPngCopy.BackBuffer;
                    int stride = BitmapPng.BackBufferStride;
                    bool candrawline = true;
                    LineLocal = "y= ";
                    for (int row = 0; row < height; row++)
                    {
                        byte rowbyte = 0x00;
                        for (int column = 0; column < width; column++)
                        {
                            byte bt = *((byte*)(pBackBuffer + row * stride + column));
                            rowbyte |= bt;
                            if (IsMakeToBinary)
                            {
                                *((byte*)(pBackBuffer + row * stride + column)) = (byte)((bt > BinaryThresholdValue) ? 0xff : 0x00);// 指针基址+地址偏移量。图像二值化处理
                            }
                        }
                        if (candrawline && row > 0 && row < height && rowbyte > HorizontalThrosholdValue)
                        {
                            for (int column = 0; column < width; column++)
                            {
                                *((byte*)(pBackBufferOfCopy + (row - 1) * stride + column)) = 0x90; // 水平辅助线
                            }
                            LineLocal += (row - 1).ToString() + ",";
                            HorizontalLocal.Add(row - 1);
                            candrawline = false;
                        }
                        candrawline = rowbyte <= HorizontalThrosholdValue;
                    }
                    LineLocal += "\nX= ";
                    candrawline = true;
                    for (int column = 0; column < width; column++)
                    {
                        byte rowbyte = 0x00;
                        for (int row = 0; row < height; row++)
                        {
                            byte bt = *((byte*)(pBackBuffer + row * stride + column));
                            rowbyte |= bt;
                        }
                        if (candrawline && column > 0 && column < width && rowbyte > VerticalThrosholdValue)
                        {
                            for (int row = 0; row < height; row++)
                            {
                                *((byte*)(pBackBufferOfCopy + row * stride + column - 1)) = 0x90; // 垂直辅助线
                            }
                            LineLocal += (column - 1).ToString() + ",";
                            VerticalLocal.Add(column - 1);
                            candrawline = false;
                        }
                        candrawline = rowbyte <= VerticalThrosholdValue;
                    }
                }
                BitmapPngCopy.AddDirtyRect(new Int32Rect(0, 0, width, height));
            }
            finally
            {
                BitmapPng.Unlock();
                BitmapPngCopy.Unlock();
            }
            if (HorizontalLocal != null && HorizontalLocal.Count > 1) // 当检测到两条以上水平辅助线时，调整取景框高度
            {
                QuJingKuangHeight = HorizontalLocal[1] - HorizontalLocal[0];
                QuJingKuangTop = HorizontalLocal[0]; // 取景框顶边贴合到第一条水平辅助线
            }
            if (VerticalLocal != null && VerticalLocal.Count > 1) // 当检测到两条以上垂直辅助线时，调整取景框宽度
            {
                QuJingKuangWidth = VerticalLocal[1] - VerticalLocal[0];
                QuJingKuangLeft = VerticalLocal[0]; // 取景框左边贴合到第一条垂直辅助线
            }
        }
        #endregion

        /// <summary>
        /// 取景框移动时，设置辅助线磁贴功能。还没想好在哪里用。
        /// </summary>
        private void AlingHelpLine()
        {
            if (HorizontalLocal != null && HorizontalLocal.Count > 0)
            {
                foreach (int row in HorizontalLocal)
                {
                    if (Math.Abs(QuJingKuangTop - row) < QuJingKuangHeight / 2)
                    {
                        QuJingKuangTop = row;
                        break;
                    }
                }
            }
            if (VerticalLocal != null && VerticalLocal.Count > 0)
            {
                foreach (int col in VerticalLocal)
                {
                    if (Math.Abs(QuJingKuangLeft - col) < QuJingKuangWidth / 2)
                    {
                        QuJingKuangLeft = col;
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// 图像二值化处理
        /// </summary>
        /// <param name="bitmap"></param>
        /// <param name="thresholdValue"></param>
        /// <returns></returns>
        public static WriteableBitmap ConvertToBinary(WriteableBitmap bitmap0, int thresholdValue)
        {
            if (bitmap0 == null) { return null; }
            WriteableBitmap bitmap=bitmap0.Clone();
            int width=bitmap.PixelWidth; int height=bitmap.PixelHeight;
            try
            {
                bitmap.Lock();
                unsafe
                {
                    IntPtr pBackBufferOfWr = bitmap.BackBuffer; // 内存指针基址
                    int stride = bitmap.BackBufferStride;
                    for (int row = 0; row < height; row++)
                    {
                        *((byte*)(pBackBufferOfWr + row * stride + 0)) = 0x00; // 左边置空
                        *((byte*)(pBackBufferOfWr + row * stride + width - 1)) = 0x00; // 右边置空
                    }
                    for (int col = 0; col < width; col++)
                    {
                        *((byte*)(pBackBufferOfWr + 0 * stride + col)) = 0x00; // 顶边置空
                        *((byte*)(pBackBufferOfWr + (height - 1) * stride + col)) = 0x00; // 底边置空
                    }
                    for (int row = 0; row < height; row++)
                    {
                        for (int col = 0; col < width; col++)
                        {
                            byte bt = *((byte*)(pBackBufferOfWr + row * stride + col));
                            *((byte*)(pBackBufferOfWr + row * stride + col)) = (byte)((bt > thresholdValue) ? 0xff : 0x00); // 首先，对图像二值化处理
                        }
                    }

                    bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height));

                }
            }
            finally { bitmap.Unlock(); }
            return bitmap;
        }

        /// <summary>
        /// 图像降噪。             
        /// 增加消除孤点的代码，即，降噪处理。如果一个空白点的上、下、左、右等四个相邻点中，有三个为非空白点，则将此空白点设置为非空白点。
        /// 反之，对于非空白点，如果与三个空白点相邻，则此点设为空白点。
        /// </summary>
        /// <param name="bitmap"></param>
        /// <param name="binaryThresholdValue"></param>
        /// <returns></returns>
        private static WriteableBitmap DeNoising(WriteableBitmap bitmap, int binaryThresholdValue)
        {
            if (bitmap == null) { return null; }
            try
            {
                bitmap.Lock();
                unsafe
                {
                    IntPtr pBackBufferOfWr = bitmap.BackBuffer; // 内存指针基址
                    int stride = bitmap.BackBufferStride;

                    for (int row = 1; row < bitmap.PixelHeight - 1; row++)
                    {
                        for (int col = 1; col < bitmap.PixelWidth - 1; col++)
                        {
                            byte bt = *((byte*)(pBackBufferOfWr + row * stride + col));
                            byte value_Left = *((byte*)(pBackBufferOfWr + (row - 0) * stride + (col - 1)));
                            byte value_Top = *((byte*)(pBackBufferOfWr + (row - 1) * stride + (col - 0)));
                            byte value_Right = *((byte*)(pBackBufferOfWr + (row + 0) * stride + (col + 1)));
                            byte value_Bottom = *((byte*)(pBackBufferOfWr + (row + 1) * stride + (col + 0)));
                            int value = value_Left + value_Right + value_Top + value_Bottom;
                            if (bt == 0x00 && value >= 0xff * 3)
                            {
                                *((byte*)(pBackBufferOfWr + row * stride + col)) = 0xff; // 对于空白点，如果相邻的3个点为非空白点，则设置为非空白点
                            }
                            if (bt == 0xff && value <= 0xff)
                            {
                                *((byte*)(pBackBufferOfWr + row * stride + col)) = 0x00; // 对于非空白点，如果相邻的3个点为空白点，则设置为空白点
                            }
                        }
                    }
                    bitmap.AddDirtyRect(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight));
                }
            }
            finally { bitmap.Unlock(); }
            return bitmap;
        }

        /// <summary>
        /// 描边
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        private static WriteableBitmap Stroke(WriteableBitmap bitmap)
        {
            if (bitmap == null) { return null; }
            WriteableBitmap outBitmap=new(bitmap.PixelWidth,bitmap.PixelHeight,bitmap.DpiX,bitmap.DpiY,bitmap.Format,bitmap.Palette);
            bitmap = ConvertToBinary(bitmap,0x00);
            bitmap = DeNoising(bitmap, 0x00);
            try
            {
                bitmap.Lock();
                outBitmap.Lock();
                unsafe
                {
                    IntPtr pBackBufferOfIn = bitmap.BackBuffer; // 内存指针基址
                    IntPtr pBackBufferOfOut = outBitmap.BackBuffer;
                    int stride = bitmap.BackBufferStride;
                    for (int row = 1; row < bitmap.PixelHeight - 1; row++)
                    {
                        for (int col = 1; col < bitmap.PixelWidth - 1; col++)
                        {
                            byte bt = *((byte*)(pBackBufferOfIn + row * stride + col));
                            if (bt > 0x00)
                            {
                                byte value_Left = *((byte*)(pBackBufferOfIn + (row - 0) * stride + (col - 1)));
                                byte value_Right = *((byte*)(pBackBufferOfIn + (row + 0) * stride + (col + 1)));
                                byte value_Top = *((byte*)(pBackBufferOfIn + (row - 1) * stride + (col - 0)));
                                byte value_Bottom = *((byte*)(pBackBufferOfIn + (row + 1) * stride + (col + 0)));
                                byte value = (byte)(value_Left & value_Right & value_Top & value_Bottom);
                                if (value == 0x00)
                                {
                                    *((byte*)(pBackBufferOfOut + row * stride + col)) = 0x10;
                                }
                            }
                        }
                    }
                    outBitmap.AddDirtyRect(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight));
                }
            }
            finally { bitmap.Unlock(); outBitmap.Unlock(); }
            return outBitmap;
        }
        /// <summary>
        /// 对于大小不统一的图块，分别找出最大边界，绘制矩形框
        /// </summary>
        /// <param name="image"></param>
        public static void BitMapSplit(BitmapImage image)
        {
            if (image == null) { return; }
            WriteableBitmap wrBitmap = new WriteableBitmap(image);
            WriteableBitmap outBitmap = new WriteableBitmap(wrBitmap.PixelWidth, wrBitmap.PixelHeight, wrBitmap.DpiX, wrBitmap.DpiY, wrBitmap.Format, wrBitmap.Palette);
            wrBitmap = ConvertToBinary(wrBitmap, 0x00); // 二值化处理

            wrBitmap = DeNoising(wrBitmap, 0); // 降噪
            const byte SPILIT_LINE_COLOR = 0x90;
            int bitmapWidth = wrBitmap.PixelWidth;
            int bitmapHeight = wrBitmap.PixelHeight;
            try
            {
                wrBitmap.Lock();
                outBitmap.Lock();
                unsafe
                {
                    int colRecode = 0;
                    int rowRecode = 0;
                    const byte BINARY_VALUE = 0x00; // 图像二值化阀值
                    IntPtr pBackBufferOfWr = wrBitmap.BackBuffer; // 内存指针基址
                    IntPtr pBackBufferOfOut = outBitmap.BackBuffer;
                    int stride = wrBitmap.BackBufferStride;

                    List<Int32Rect> rects = new List<Int32Rect>(); // 图块矩形框

                    for (int row = 1; row < bitmapHeight - 1; row++) // 自顶向下扫描，边界不处理（因为在二值化时，边界已置空）
                    {
                        for (int col = 1; col < bitmapWidth - 1; col++)
                        {
                            byte bt = *((byte*)(pBackBufferOfWr + row * stride + col));
                            if (bt > BINARY_VALUE)
                            {
                                rowRecode = row; // 找到第一个有值像素，作为图像切片的top
                                break;
                            }
                        }
                        Int32Rect rect = new(colRecode, rowRecode, 0, 0);
                        int col1 = colRecode, row1 = rowRecode;
                        //col1++; // 围绕图像，顺时针查找轮廓
                        while (col1 != colRecode && row1 != rowRecode) // 查找图像轮廓，获得矩形边界数据
                        {
                            byte value_Left = *((byte*)(pBackBufferOfWr + (row1 - 0) * stride + (col1 - 1)));
                            byte value_Top = *((byte*)(pBackBufferOfWr + (row1 - 1) * stride + (col1 - 0)));
                            byte value_Right = *((byte*)(pBackBufferOfWr + (row1 - 0) * stride + (col1 + 1)));
                            byte value_Bottom = *((byte*)(pBackBufferOfWr + (row1 + 1) * stride + (col1 - 0)));
                            if ((value_Left | value_Right | value_Top | value_Top) > BINARY_VALUE)
                            {
                                if (value_Right == BINARY_VALUE)
                                {
                                    col1++;
                                }
                                else if (value_Left == BINARY_VALUE)
                                {
                                    col1--;
                                }
                                else if (value_Top == BINARY_VALUE)
                                {
                                    row1--;
                                }
                                else if (value_Bottom == BINARY_VALUE)
                                {
                                    row1++;
                                }
                                else
                                {
                                    col1++; row1++;
                                }
                            }

                            rect.X = Math.Min(rect.X, col1);
                            rect.Width = Math.Max(rect.Width, Math.Abs(rect.X - col1));
                            rect.Height = Math.Max(rect.Height, Math.Abs(rect.Y - row1));
                        }
                        rects.Add(rect);

                    }

                    foreach (Int32Rect rect in rects)
                    {
                        for (int i = 0; i < rect.Width; i++) // 画水平边框
                        {
                            *((byte*)(pBackBufferOfOut + rect.Y * stride + rect.X + i)) = SPILIT_LINE_COLOR;
                            *((byte*)(pBackBufferOfOut + (rect.Y + rect.Height) * stride + i)) = SPILIT_LINE_COLOR;
                        }
                        for (int j = 0; j < rect.Height; j++) // 画垂直边框
                        {
                            *((byte*)(pBackBufferOfOut + (rect.Y + j) * stride + rect.X)) = SPILIT_LINE_COLOR;
                            *((byte*)(pBackBufferOfOut + (rect.Y + j) * stride + rect.X + rect.Width)) = SPILIT_LINE_COLOR;
                        }

                    }

                }
                wrBitmap.AddDirtyRect(new Int32Rect(0, 0, wrBitmap.PixelWidth, wrBitmap.PixelHeight));
                outBitmap.AddDirtyRect(new Int32Rect(0, 0, outBitmap.PixelWidth, outBitmap.PixelHeight));
            }
            finally
            {
                wrBitmap.Unlock();
                outBitmap.Unlock();
            }


        }
        public class MyRect
        {
            public int Left;
            public int Right;
            public int Top;
            public int Bottom;
            public MyRect()
            {
                Left = 0;
                Right = 0;
                Top = 0;
                Bottom = 0;
            }
            public MyRect(int left, int right, int top, int bottom)
            {
                Left = left;
                Right = right;
                Top = top;
                Bottom = bottom;
            }
        }

        #region 备用函数，可从文件加载图像到WriteableBitmap
        //此方法运行效果很好，达到了可以频繁显示经更改数据（但照片路径不变）后的照片的目的       
        // 原文链接：https://blog.csdn.net/jiuzaizuotian2014/article/details/108049446
        public static BitmapImage GetBitmapImage(string imagePath)
        {
            FileStream fs = null;
            try
            {
                fs = new FileStream(imagePath, FileMode.Open);
                byte[] MyData = new byte[fs.Length];
                fs.Read(MyData, 0, (int)fs.Length);

                MemoryStream ms = new MemoryStream(MyData);
                BitmapImage bitmap = new BitmapImage();  //WPF
                bitmap.BeginInit();
                bitmap.CacheOption = BitmapCacheOption.OnLoad;
                bitmap.StreamSource = ms;
                bitmap.EndInit();
                return bitmap;
            }
            catch (Exception ex)
            {
                // Exception treatment code here
                Debug.Print(imagePath + ": " + ex.Message);
                return null;
            }
            finally
            {
                fs?.Close();
            }
        }
        #endregion


    }
}
